﻿using Serialize.Library;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

namespace Validate.Library
{
    public static class ValidateHelper
    {
        /// <summary>
        /// 验证实体对象的所有带验证特性的元素  并返回验证结果  如果返回结果为String.Empty 则说明元素符合验证要求
        /// </summary>
        /// <param name="entityObject">实体对象</param>
        /// <returns></returns>
        public static void Validate<T>(this T tModel) where T : new()
        {
            if (tModel == null)
                throw new ArgumentNullException("entityObject");

            Type type = tModel.GetType();

            var parmerters= tModel.ToJson().JsonToObject<Dictionary<String, Object>>();

            GetValidateResult(type, parmerters);
        }

        /// <summary>
        /// 获取结果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="typeInfo"></param>
        /// <param name="tModel"></param>
        /// <param name="dic"></param>

        private static void GetValidateResult(Type typeInfo,Dictionary<string, object> dic)
        {
            foreach (PropertyInfo property in typeInfo.GetProperties())
            {
                ///如果是一般类型，非实体类型 或list类型
                if (property.PropertyType.FullName.Contains("System.") && property.PropertyType.FullName.IndexOf("System.Collections.Generic.") == -1)
                {
                    if (property.IsDefined(typeof(Attribute), true))
                    {
                        //获取验证特性
                        var validateContent = property.GetCustomAttributes(typeof(ValidateAttribute), true);

                        object[] objs = property.GetCustomAttributes(typeof(DescriptionAttribute), true);

                        if (validateContent != null)
                        {
                            //获取属性的值
                            var value = dic[property.Name];

                            foreach (ValidateAttribute validateAttribute in validateContent)
                            {
                                ValidateAttribute(validateAttribute,value);
                            }
                        }
                    }
                }
                else
                {
                    ///如果是list
                    if (property.PropertyType.FullName.IndexOf("System.Collections.Generic.") > -1)
                    {
                        string fullName = property.PropertyType.FullName.Substring(property.PropertyType.FullName.IndexOf("[[") + 2,
                                                        property.PropertyType.FullName.LastIndexOf("]]") - property.PropertyType.FullName.IndexOf("[[") - 2);

                        fullName = fullName.Substring(0, fullName.IndexOf(","));

                        if (fullName.Contains("System."))//为true，表示是.net的原生类型，即基础类型，注意string类型，自定义的struct，class不是原生类型
                        {
                            if (string.IsNullOrEmpty(dic[property.Name].ToString()))
                            {
                               throw new ValidateException($"{property.Name}不能为空");
                            }
                        }
                        else
                        {
                            var vaules = dic[property.Name].ToJson().JsonToObject<List<Dictionary<String, Object>>>();
                            foreach (var item in vaules)
                            {
                                Type requestModel = Assembly.Load(fullName.Substring(0, fullName.LastIndexOf('.'))).CreateInstance(fullName, false).GetType();
                                GetValidateResult(requestModel, item);
                            }
                        }
                    }
                    //非list实体
                    else
                    {
                        var vaules = dic[property.Name].ToJson().JsonToObject<Dictionary<String, Object>>();
                        GetValidateResult(property.PropertyType, vaules);
                    }
                }
            }
        }


        /// <summary>
        /// 验证属性
        /// </summary>
        /// <param name="validateAttribute"></param>
        /// <param name="value"></param>
        private static void ValidateAttribute(ValidateAttribute validateAttribute,object value)
        {

            switch (validateAttribute.ValidateType)
            {
                //验证元素是否为空字串
                case ValidateType.NotEmpty:
                    if (null == value || value.ToString().Length < 1)
                        throw new ValidateException($"【{validateAttribute.Description}】不能为空");
                    break;
                //验证元素的长度是否小于指定最小长度
                case ValidateType.MinLength:
                    if (null == value || value.ToString().Length < 1) break;
                    if (value.ToString().Length < validateAttribute.MinLength)
                        throw new ValidateException($"【{validateAttribute.Description}】的长度不能小于{validateAttribute.MinLength}");
                    break;
                //验证元素的长度是否大于指定最大长度
                case ValidateType.MaxLength:
                    if (null == value || value.ToString().Length < 1) break;
                    if (value.ToString().Length > validateAttribute.MaxLength)
                        throw new ValidateException($"【{validateAttribute.Description}】的长度不能大于{validateAttribute.MaxLength}");
                    break;
                //验证元素的长度是否符合指定的最大长度和最小长度的范围
                case ValidateType.MinLength | ValidateType.MaxLength:
                    if (null == value || value.ToString().Length < 1)
                        break;
                    if (value.ToString().Length > validateAttribute.MaxLength || value.ToString().Length < validateAttribute.MinLength)
                        throw new ValidateException($"【{validateAttribute.Description}】不符合指定的最小长度和最大长度的范围,应该在{validateAttribute.MinLength}与{validateAttribute.MaxLength} 之间");
                    break;

                //验证正则表达式
                case ValidateType.MatchingRegex:
                    if (!System.Text.RegularExpressions.Regex.IsMatch(value.ToString(), validateAttribute.Regex))
                        throw new ValidateException($"请输入：【{validateAttribute.Description}】");
                    break;

                //验证正则表达式+MinLength
                case ValidateType.MatchingRegex | ValidateType.MinLength:

                    if (value.ToString().Length < validateAttribute.MinLength)
                    {
                        goto case ValidateType.MinLength;
                    }
                    goto case ValidateType.MatchingRegex;

                //验证正则表达式+MaxLength
                case ValidateType.MatchingRegex | ValidateType.MaxLength:

                    if (value.ToString().Length > validateAttribute.MaxLength)
                    {
                        goto case ValidateType.MaxLength;
                    }
                    goto case ValidateType.MatchingRegex;

                //验证正则表达式+MinLength|MaxLength
                case ValidateType.MatchingRegex | ValidateType.MinLength | ValidateType.MaxLength:
                    if (!System.Text.RegularExpressions.Regex.IsMatch(value.ToString(), validateAttribute.Regex))
                    {
                        goto case ValidateType.MatchingRegex;
                    }
                    goto case ValidateType.MinLength | ValidateType.MaxLength;

                //验证元素的值是否在指定的数据源中
                case ValidateType.InCustomArray:
                    if (null == value || value.ToString().Length < 1)
                        break;
                    if (null == validateAttribute.CustomArray || validateAttribute.CustomArray.Length < 1)
                        throw new ValidateException($"系统内部错误{validateAttribute.Description}指定的数据源为空或没有数据");

                    bool isHas = Array.Exists<string>(validateAttribute.CustomArray,(str) => { return str == value.ToString(); });
                    if (!isHas)
                        throw new ValidateException($"【{validateAttribute.Description}】的值不正确,应该为：{string.Join(",", validateAttribute.CustomArray)}中的一种");
                    break;

                //验证元素是否为空且符合指定的最小长度
                case ValidateType.NotEmpty | ValidateType.MinLength:
                    if (null == value || value.ToString().Length < 1) {
                        goto case ValidateType.NotEmpty;
                    }
                    goto case ValidateType.MinLength;

                //验证元素是否为空且符合指定的最大长度
                case ValidateType.NotEmpty | ValidateType.MaxLength:
                    if (null == value || value.ToString().Length < 1)
                        goto case ValidateType.NotEmpty;
                    goto case ValidateType.MaxLength;

                //验证元素是否为空且符合指定的长度范围
                case ValidateType.NotEmpty | ValidateType.MinLength | ValidateType.MaxLength:
                    if (null == value || value.ToString().Length < 1)
                        goto case ValidateType.NotEmpty;
                    goto case ValidateType.MinLength | ValidateType.MaxLength;

                //验证元素是否为空且值在指定的数据源中
                case ValidateType.NotEmpty | ValidateType.InCustomArray:
                    if (null == value || value.ToString().Length < 1)
                        goto case ValidateType.NotEmpty;
                    goto case ValidateType.InCustomArray;

                default:
                    break;
            }
        }
    }
}
